/**
 * RMI SERVER  - THE RACE RESERVATION SERVER IN THE ARCHITECTURE
 * CONNECTION TO: RMI AUTHORIZATION SERVER AND AUTHORIZATION WEB SERVICE
 * CONNECTION TO: CORBA RUNNING RACE SERVER COMPONENT
 * CONNECTION TO: ARABARACES WEB SERVICE
 * USE THE COMMAND INTERFACE TO KEEP A TRACE OF THE SERVER ACTIVITIES
 */
package raceReservationServer;

import java.rmi.RemoteException;
import java.util.TreeMap;
import java.rmi.server.UnicastRemoteObject;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import util.observer.rmi.RemoteObservable;
import raceReservationServer.dao.*;
import raceReservationServer.loginGateway.AuthorizationGatewayFactory;
import raceReservationServer.loginGateway.IAuthorizeGateway;
import raceReservationServer.loginGateway.RunnerDO;
import raceReservationServer.loginGateway.ValidationException;
import raceReservationServer.raceServerGateway.RaceServerGatewayFactory;
import raceReservationServer.raceServerGateway.IRaceServerGateway;
import java.util.LinkedList;
import raceReservationServer.raceServerGateway.RaceDO;
import raceReservationServer.saxParser.GatewayObject;
import raceReservationServer.saxParser.RaceServerGatewaysSAXHandler;

import java.rmi.RMISecurityManager;
import java.rmi.Naming;
import java.sql.SQLException;
import java.net.MalformedURLException;

import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;

import util.observer.rmi.IRemoteObserver;

import org.omg.CosNaming.*;

import RMIClient.RunnerRMIDTO;
import authorizationRMI.InvalidPasswordException;
import authorizationRMI.InvalidUserException;
import corbaServer.corba.*;
import org.omg.CORBA.ORB;


public class ReservationRaceServer extends UnicastRemoteObject implements IReservationRaceServer{

	/**
	 * CACHE OF RaceRMIDTO objects, organized by Running Race Name To be
	 * loaded at the initialization process
	 */
	private static Map<String, Map<String, RaceRMIDTO>> racesCache;
	private static final long serialVersionUID= 1L;
	private static IRaceServerDAO iRaceServerDAO= new RaceServerDAO();
	
	private static AuthorizationGatewayFactory authGateFact= AuthorizationGatewayFactory.getInstance(); 
	private RemoteObservable remoteObservable;
	private static IAuthorizeGateway iAuthGate; 
	private static RaceServerGatewayFactory gateFact= RaceServerGatewayFactory.getInstance();
	public ReservationRaceServer() throws RemoteException{
		super();
		this.remoteObservable= new RemoteObservable();
		this.racesCache=new TreeMap<String, Map<String, RaceRMIDTO>>();
	}

	public static void main(String[] args){
		ReservationRaceServer rServ= null;
		try {
			rServ = new ReservationRaceServer();
		} catch (RemoteException e1) {
			System.out.println("ReservationRaceServer constructor error");
		}
		try {
			//CÓDIGO DEL CLIENTE!!!
			
			
			SAXParserFactory factory = SAXParserFactory.newInstance();        
	        factory.setValidating(true);
	        ArrayList<GatewayObject> gObjects;
	        
	        try {
	        	System.out.println("ANALISIS DE UN DOCUMENTO XML USANDO SAX");
				System.out.println("-------- -- -- --------- --- ------ ---");            
	        	SAXParser saxParser = factory.newSAXParser();
	            RaceServerGatewaysSAXHandler handler = new RaceServerGatewaysSAXHandler();                        
	            saxParser.parse("src/raceReservationServer/saxParser/xmlgateways.xml", handler);
	            gObjects = (ArrayList<GatewayObject>)handler.getGateway();
	            for (int i=0; i<gObjects.size(); i++){
		            System.out.println("\n * Creating gateway: '" + gObjects.get(i).getName() + "'");
		            String uri=gObjects.get(i).getUrl() +" "+ gObjects.get(i).getPort()+" " + gObjects.get(i).getName();
		            System.out.println("The uri: " + uri);
		            IRaceServerGateway iGateway= gateFact.getRaceServerGateway(uri, gObjects.get(i).getTech());
//					IRaceServerGateway iGateway= gateFact.getRaceServerGateway("127.0.0.1 900 bizkaiaraces", "corba");
					rServ.cacheBuilder(iGateway, gObjects.get(i).getName());
//					rServ.cacheBuilder(iGateway,"bizkaiaraces");
				}
	        } catch (Exception e) {
	            System.out.println("Error -> Main():" + e.getMessage());
	            e.printStackTrace();
	        }
			
			
			
			
			//Hemos quitado espacios entre los parámetros
//			IRaceServerGateway iGateway= gateFact.getRaceServerGateway(args[0] + args[1] + args[2], "jms");
			//  Obviamos el metodo getAuthGateway con el String ya formateado para crear otro sin formatear el String
			//	iAuthGate = authGateFact.getAuthGateway("//"+args[3]+":" + args[4] + "/" + args[5], "rmi");
			iAuthGate = authGateFact.getAuthGateway(args[0]+" "+args[1]+" "+args[2], args[3]);
//			rServ.cacheBuilder(iGateway, args[2]);
		} catch(Exception e) {
			System.out.println("ERROR: " + e);
				e.printStackTrace(System.out);
		}
		if(System.getSecurityManager()==null){
			System.setSecurityManager(new RMISecurityManager());
		}
		//Lanzar RMI
		String name= "//" + args[0] + ":" + "1099" + "/" + "ServerRMI";
		System.out.println("ServerRMI launched..." + name);
		try{
			IReservationRaceServer rRaceServer= new ReservationRaceServer();
			Naming.rebind(name, rRaceServer);
//			Naming.rebind("//127.0.0.1:1099/ServerRMI", reservationRaceServer);
		}catch(RemoteException re){
			System.err.println("Remote exception: " + re.getMessage());
			System.exit(-1);
		}catch(MalformedURLException mu){
			System.err.println("Malformed url exception: " + mu.getMessage());
			System.exit(-1);
		}
		
		//Insertamos una reserva
//		rServ.reservePlace("El Txuls", "GipuzkoaRaces", "Behobia-San Sebastián");
		
	}
	public Map<String, Map<String, RaceRMIDTO>> getMap(){
		return this.racesCache;
	}
	
	public void addRemoteObserver(IRemoteObserver ir)throws RemoteException{
		this.remoteObservable.addRemoteObserver(ir);
	}
	
	public void deleteRemoteObserver(IRemoteObserver ir) throws RemoteException{
		this.remoteObservable.deleteRemoteObserver(ir);
	}
	
	public RunnerRMIDTO login(String user, String pass) throws InvalidUserException, InvalidPasswordException, RemoteException{
		
		RunnerDO runnerDO;
		try {
			runnerDO = iAuthGate.login(user, pass);
		} catch (InvalidUserException e) {
			// TODO Auto-generated catch block
			throw e;
		} catch (InvalidPasswordException e) {
			// TODO Auto-generated catch block
			throw e;
		}
		RunnerRMIDTO runner= new RunnerRMIDTO(runnerDO.getUsername(), runnerDO.getPassword(), runnerDO.getName(), runnerDO.getAge(), runnerDO.getSex());
		return runner;
	}
	
	public List<RaceRMIDTO> getRaces(){
		Map<String, RaceRMIDTO> aux= null;
		Collection<Map<String,RaceRMIDTO>> col= racesCache.values();
		Iterator<Map<String,RaceRMIDTO>> it = col.iterator();
		Collection <RaceRMIDTO> colRace;
		Iterator<RaceRMIDTO> itRace;
		RaceRMIDTO auxRace;
		LinkedList<RaceRMIDTO> list= new LinkedList<RaceRMIDTO>();
		while(it.hasNext()){
			aux = it.next();
			colRace= aux.values();
			itRace= colRace.iterator();
			while (itRace.hasNext()){
				auxRace=itRace.next();
				list.add(auxRace);
			}
		}
		return list;
	}
	
	public void cacheBuilder(IRaceServerGateway iGateway, String serverName){ 
		LinkedList<RaceDO> raceList=(LinkedList<RaceDO>)iGateway.getRaces();
		String rServer;
		String rName;
		float rDist;
		String rDate;
		int rPlaces=0;
		
		//Creamos los RMIDTO y rellenamos la caché
		Map<String, RaceRMIDTO> insideMap= new TreeMap<String, RaceRMIDTO>();
		for(int i=0; i< raceList.size(); i++){
			System.out.println(raceList.get(i).getName());
			RaceDO aux= raceList.get(i);
			//Lo coge de la llamada al crear el IRaceServerGateway
			rServer= serverName;
			rName= aux.getName();
			rDist= aux.getDistance();
			rDate= aux.getDate();
			int capacity= aux.getaAvailablePlaces();
			System.out.println("Capacity= " + capacity);
			int reservedPlaces;
			try {
				reservedPlaces = iRaceServerDAO.getPlacesCount(serverName,rName);
				System.out.println("Reserved places= " + reservedPlaces);
				rPlaces= capacity - reservedPlaces;
				System.out.println("Available places for " + rName + " race: " + rPlaces + "\n");
				RaceRMIDTO rmiDTO= new RaceRMIDTO(rServer, rName, rDist, rDate, rPlaces);
				
				insideMap.put(rName, rmiDTO);
				
			} catch (SQLException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}		
		}
		racesCache.put(serverName, insideMap);
		if (racesCache.isEmpty()){
			System.out.println("The cache is empty\n");
		}
		else System.out.println("The cache is filled up\n");
	}
	
	public void reservePlace(String runnerName, String raceServer, String raceName)throws SQLException{
		int fallo=0;
		try {
			iRaceServerDAO.reservePlace(runnerName, raceServer, raceName);
		} catch (SQLException e) {
			// TODO Auto-generated catch block
		    fallo=1;
		    throw e;
		}
		if (fallo==0){
			Map<String, RaceRMIDTO> auxMap;
			auxMap=racesCache.get(raceServer);
			RaceRMIDTO aux = auxMap.get(raceName);
			aux.setAvailablePlaces(aux.getAvailablePlaces()-1);
			auxMap.put(raceName, aux);
			racesCache.put(raceServer, auxMap);
			System.out.println("The reservation has been successfuly done");
			this.remoteObservable.notifyRemoteObservers(aux);
		}
	}
	
//	private void notify(RaceRMIDTO race){
//		this.remoteObservable.notifyRemoteObservers(race);
//	}
}
